#include "d3d.h"

LPCWSTR		str1 = L"apple.jpg";
LPCWSTR		str2 = L"saton.jpg";
LPCWSTR		str3 = L"qt.jpg";

MyD3D::MyD3D()
{
	lpd3d				= NULL;
	lpd3ddevice		= NULL;
	lpVB				= NULL;
	lpTexture			= NULL;
}

MyD3D::~MyD3D()
{
	ReleaseD3D();
}


HRESULT MyD3D::InitD3D(HWND hWnd)
{
	if (FAILED(lpd3d = Direct3DCreate9(D3D_SDK_VERSION)))
		return E_FAIL;
	
	D3DPRESENT_PARAMETERS 	d3dpp;

	ZeroMemory(&d3dpp, sizeof(d3dpp));
	d3dpp.Windowed = TRUE;
	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
	d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
	/*d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
*/

	HRESULT		hRes;
	hRes = lpd3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, 
										  D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                          &d3dpp, &lpd3ddevice);

   if (FAILED(hRes))
	   return E_FAIL;


    // Turn off culling
    lpd3ddevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );

#ifdef ADD_NORMAL
	// Turn on Z-buffer
    lpd3ddevice->SetRenderState( D3DRS_ZENABLE, FALSE );
#else
	lpd3ddevice->SetRenderState( D3DRS_LIGHTING, FALSE );
	lpd3ddevice->SetRenderState( D3DRS_ZENABLE, TRUE );
#endif
	return S_OK;
}

HRESULT	MyD3D::SetMappingData()
{
	if ( FAILED ( D3DXCreateTextureFromFile (lpd3ddevice, str1, &lpTexture) ) )
	{
		MessageBox( NULL, L"Could not find saton.jpg", L"Textures.exe", MB_OK );
            return E_FAIL;
	}
	return S_OK;
}


// Init vertex Data
HRESULT	MyD3D::InitVB()
{
	SetMappingData();
	
	if ( FAILED (lpd3ddevice->CreateVertexBuffer( 4 * sizeof(MyVertex), 0, D3DFVF_MYVERTEX,
													      D3DPOOL_DEFAULT, &lpVB, NULL)))
	{
		return E_FAIL;
	}

	MyVertex*      pvertex;
	
	if (FAILED (lpVB->Lock(0, 0, (void**)&pvertex, 0 ) ) )
		return E_FAIL;

	pvertex[0].position = D3DXVECTOR3(-1.0f, 1.0f, 0.0f);
	pvertex[1].position = D3DXVECTOR3(1.0f, 1.0f, 0.0f);
	pvertex[2].position = D3DXVECTOR3(-1.0f,-1.0f, 0.0f);
	pvertex[3].position = D3DXVECTOR3(1.0f, -1.0f, 0.0f);

#ifdef TEX_ADDRESS
	pvertex[0].tu         = 0.0f;
	pvertex[0].tv         = 0.0f;
	pvertex[1].tu         = 3.0f;
	pvertex[1].tv         = 0.0f;
	pvertex[2].tu         = 0.0f;
	pvertex[2].tv         = 3.0f;
	pvertex[3].tu         = 3.0f;
	pvertex[3].tv         = 3.0f;
#else
	pvertex[0].tu         = 0.0f;
	pvertex[0].tv         = 0.0f;
	pvertex[1].tu         = 1.0f;
	pvertex[1].tv         = 0.0f;
	pvertex[2].tu         = 0.0f;
	pvertex[2].tv         = 1.0f;
	pvertex[3].tu         = 1.0f;
	pvertex[3].tv         = 1.0f;
#endif
#ifdef ADD_NORMAL
	pvertex[0].normal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
	pvertex[1].normal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
	pvertex[2].normal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
	pvertex[3].normal = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
//
//	/*pvertex[0].color     = 0x00ff0000; 
//	pvertex[1].color     = 0x00ff0000;
//	pvertex[2].color     = 0x00ff0000;
//	pvertex[3].color     = 0x00ff0000;*/
//
//
//
//	    
#endif
	lpVB->Unlock();

	return S_OK;
}

void MyD3D::SetMatrices()
{
	// world transform
	UINT		time = timeGetTime() % 1000;
	//float		angle = time *  ( 2.0f * D3DX_PI ) / 1000.0f;   // 1 full rotation every 1000ms
	float		angle =   ( 2.0f * D3DX_PI );   // 1 full rotation every 1000ms
	D3DXMatrixRotationY( &matWorld, angle);
	lpd3ddevice->SetTransform ( D3DTS_WORLD, &matWorld);

	// view transform
	D3DXVECTOR3		eye (0.0f, 0.0f, -5.0f);
	D3DXVECTOR3		LookAt (0.0f, 0.0f, 0.0f);
	D3DXVECTOR3		Up (0.0f, 0.5f, 0.0f);

	D3DXMatrixLookAtLH(&matView, &eye, &LookAt, &Up);
	lpd3ddevice->SetTransform (D3DTS_VIEW, &matView);

	// Projection
	D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 100.0f);
	lpd3ddevice->SetTransform(D3DTS_PROJECTION, &matProj);
}

void MyD3D::SetLights()
{
	ZeroMemory( &mtrl, sizeof( mtrl ) );

	mtrl.Ambient.r = mtrl.Diffuse.r = 1.0f;
	mtrl.Ambient.g = mtrl.Diffuse.g =1.0f;
	mtrl.Ambient.b = mtrl.Diffuse.b = 1.0f;
	mtrl.Ambient.a = mtrl.Diffuse.a = 1.0f;
	lpd3ddevice->SetMaterial( &mtrl );

	D3DXVECTOR3		direction;
	ZeroMemory( &light, sizeof( light ) );
	light.Type = D3DLIGHT_DIRECTIONAL;
	light.Direction = D3DXVECTOR3 ((timeGetTime () /350.0f ), 1.0f, 1.0f);
//	light.Direction = D3DXVECTOR3 (1.0f, 1.0f, 1.0f);
	D3DXVec3Normalize( (D3DXVECTOR3*)&light.Direction, &direction);
	light.Diffuse.r = 1.0f;
	light.Diffuse.g = 0.0f;
	light.Diffuse.b = 0.0f;
	light.Range = 100.0f;

	lpd3ddevice->SetLight( 0, &light );
	lpd3ddevice->LightEnable( 0, TRUE );
	lpd3ddevice->SetRenderState( D3DRS_LIGHTING, TRUE );

	lpd3ddevice->SetRenderState( D3DRS_AMBIENT, 0x00202020 );
}

void MyD3D::SetTexturing()
{
	// Texturing
	lpd3ddevice->SetTexture(0, lpTexture);
	lpd3ddevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
	lpd3ddevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	lpd3ddevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
	lpd3ddevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

}

void MyD3D::SetTextureAddress(int mode)
{
#ifdef TEX_ADDRESS
	switch (mode)
	{
	case 1:
		// Wrapping
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
		break;

	case 2:
		// Mirroring
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_MIRROR);
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_MIRROR);
		break;

	case 3:
		//Clamp
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
		break;

	case 4:
		// Border Color
		lpd3ddevice->SetSamplerState(0, D3DSAMP_BORDERCOLOR, 0x0000ffbf);
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_BORDER);
		lpd3ddevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_BORDER);
		break;
	}
#endif
}

// Rendering Func
HRESULT MyD3D::Render()
{
	if (!lpd3ddevice)
		return E_FAIL;

	lpd3ddevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
	lpd3ddevice->BeginScene();
	
#ifdef ADD_NORMAL
	SetLights();
#endif
	// Transform
	SetMatrices();

	// Set Texture
	SetTexturing();

	// rendering here
	lpd3ddevice->SetStreamSource(0, lpVB, 0, sizeof ( MyVertex ));
	lpd3ddevice->SetFVF (D3DFVF_MYVERTEX);
	lpd3ddevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, 0, 2 );
	
	lpd3ddevice->EndScene();
	
	lpd3ddevice->Present(NULL, NULL, NULL, NULL);

	return S_OK;
}

void	MyD3D::ReleaseD3D()
{
	if (lpTexture)
		lpTexture->Release();
	if (lpVB)
		lpVB->Release();
	if (lpd3ddevice)
		lpd3ddevice->Release();
	if (lpd3d)
		lpd3d->Release();
}